#ifndef VIEWER_H
#define VIEWER_H

#include <QGLViewer/qglviewer.h>

#include <QGLShaderProgram>

#include <vector>

#include "OpenMeshWrapper.h"
#include "DeformationGraph.h"
#include "lbfgsb.h"

#include <geodesic_algorithm_exact.h>

#define DIS_THRESHOLD 20
#define ANG_THRESHOLD 0.6

typedef std::pair<Vector3d, Vector3d> Handle;
// first[0] = is selected?
// first[1] = index of template point
// first[2] = is on target mesh?
// second   = correspond point

class DeformableRegistration;
class Viewer : public QGLViewer
{
    Q_OBJECT

public:
	Viewer(QWidget *parent = 0);
// 	~Viewer(){Clear();CleanShader();};
	DeformableRegistration* pParentDlg;

	void Clear();

protected :	
	virtual void init();
	virtual void draw();
	virtual void drawWithNames();	

	// sub draw functions
	void DrawMesh();
	void DrawDeformationGraph();
	void DrawHandles(double r);
	void DrawGeodesicPath(double r);
	void DrawCorrenpondence();	


	// mouse interaction
	bool onDrag;
	Qt::MouseButton btn_pressed;
	qglviewer::Vec mouse_curr;
	qglviewer::Vec mouse_prev;

	virtual void mousePressEvent(QMouseEvent* e);
	virtual void mouseMoveEvent(QMouseEvent *e);
	virtual void mouseReleaseEvent(QMouseEvent *e);		

public:
	CTriMesh templ;
	CTriMesh templ_deformed;
	CTriMesh target;
	DeformationGraph graph;

	// shader
	QGLShader* VertexShader;
	QGLShader* FragmentShader;
	QGLShaderProgram* shader_program;
	void LoadShader(QString vshader, QString fshader);
	void CleanShader();

	int nearest_k; // for k-nearest nodes of deformation graph
	std::vector<std::vector<int>> k_nearest_idx;
	std::vector<std::vector<double>> weight_value;

	 // optimization conditions
	double alph[6];
	ap::real_1d_array x;
	ap::integer_1d_array nbd;
	ap::real_1d_array lbd, ubd;
	double epsg;
	double epsf; // 10^-9
	double epsx;
	int maxits;


	/////////////////
	// Summner part//
	/////////////////
	bool onEmbededDeformation;
	std::vector<Handle> handles;

	void InitOptimization();
	void RunOptimization();
	void Deform(const CTriMesh& ori, const ap::real_1d_array& x, CTriMesh& mesh, DeformationGraph& dgraph);

	/////////////////
	// Hoa Li part //
	/////////////////
	bool onHaoli;	
	std::vector<std::pair<int, int>> correnpondence;
	
	void InitOptimization_HaoLi();
	void RunOptimization_HaoLi();

	//////////////////
	// Geodesic part//
	//////////////////
	bool onGeodesic;
	std::vector<int> source_vertex_index;
	std::vector<int> target_vertex_index;
	void InitGeo();
	void Propagate();
};

#endif // VIEWER_H